package com.bhugo;

import java.util.Comparator;

/**
 * @author benjamin
 * Abstract data type to store an IPv4 address as a single 32-bit integer.
 * Packing 4 bytes into a 32-bit int will reduce an equality check from 4 checks to 1  
 */
public class IPStore implements Comparable<IPStore> {
	private int _addr;
	/**
	 * Splits an IP address on points, white space or commas
	 * Assumes: IP has already been separated from rest of text, but may contain extra whitespace on either side
	 * @param ip
	 * @return array of four string elements representing the components of the IPv4 address
	 */
	public static String[] splitIPv4Address(String ip){
		return ip.trim().split("\\.+|\\s+|,+");
	}
	/**
	 * Default constructor (packs the provided IP into a 32-bit space for memory efficiency)
	 * @throws IllegalArguementException when the components of the IPv4 address constitutes 
	 * values larger than 255, smaller than 0 or not equal to 4 components 
	 * @param ip: a string array of 4 numbers between 0 and 255 
	 */
	public IPStore(String[] ip){
		if (ip.length != 4)
			throw new IllegalArgumentException("input must contain a valid 4 component IPv4 address");
		int[] convertedIP = {Integer.parseInt(ip[0]),Integer.parseInt(ip[1]),
				Integer.parseInt(ip[2]),Integer.parseInt(ip[3])};
		for (int i = 0; i < 4; ++i)
			if (convertedIP[i] < 0 || convertedIP[i] > 255)
				throw new IllegalArgumentException("Components of an IPv4 must be values in the range 0..255");
		
		_addr = convertedIP[0] << 24 | 
				convertedIP[1] << 16 |
				convertedIP[2] << 8  |
				convertedIP[3];
	}
	/**
	 * Copy constructor
	 * @param ip
	 */
	public IPStore(IPStore ip){
		_addr = ip._addr; 
	}
	@Override
	public String toString(){
		return String.valueOf((_addr >>> 24) & 0x000000ff)+'.'+
			   String.valueOf((_addr >>> 16) & 0x000000ff)+'.'+
			   String.valueOf((_addr >>> 8) & 0x000000ff)+'.'+
			   String.valueOf((_addr) & 0x000000ff);
	}
	@Override
	public boolean equals(Object o){
		if (!(o instanceof IPStore))
			throw new IllegalArgumentException("Expected type "+this.getClass().getName()+" but found "+o.getClass().getName());
		IPStore other = (IPStore)o;
		return (this._addr == other._addr); 
	}
	@Override
	public int hashCode(){
		return _addr;
	}
	/**
	 * Accessor for packed address value
	 * @return packed 32-bit integer representation of IPv4 address
	 */
	public int get_addr() {
		return _addr;
	}
	@Override
	public int compareTo(IPStore arg0) {
		return _addr - arg0._addr;
	}
}
